import projects from '@/models/projects';
import storyWithproject from '@/models/storyWithproject';
import mergeLog from '@/models/mergeLog';
import dayjs, { Dayjs } from 'dayjs';
import { analysisToken } from '@/utils/Auth/auth';
import { ObjectId } from 'mongodb';
import { addLogs } from '@/services/logs';
import { syncGetPersons } from '@/services/personManage/index';
import { privateToken } from '../configs/gitlab';
import { getProjects, getGroups, getBranchesList, getBranchCommitList, getBranchCommitLastest, postNewBranch, getSingleBranch, postNewMR, getRefs, getProjectDetailById } from './apis';
import { sendMsgMergeDone, sendMsgUnMergeLog, ddSendMergeMasterCountMsg } from '../dingtalk/func';
import { queryDingTalkIdByUserNames } from '../dingtalk/apis';

// 判断字符串中是不是含有uat相关的字符串
const isUat = (str: string) => /(mergeuat|uat)/gi.test(str);

const compareProject = async (list, index: number) => {
  const item = list[index];
  const oldItem = await projects.findOne({ id: item.id });
  if (!oldItem) {
    const obj = item;
    obj.envs = [];
    obj.showInMind = 0;
    obj.storage_at = new Date();
    obj.last_sync_at = new Date();
    await projects.insert(obj);
  } else {
    const obj = item;
    obj.last_sync_at = new Date();
    await projects.update(obj, { id: obj.id });
  }
  if (index < list.length - 1) {
    await compareProject(list, index + 1);
  }
};

// 循环从gitlab拉取项目。如果大于100条的话
const pullProject = async (page) => {
  const list = await getProjects({
    private_token: privateToken,
    per_page: 100,
    page,
  });
  if (list.length <= 0) return [];
  // const oldList = await projects.getList(undefined, undefined, page, 100);
  // const existIds = oldList.map((t) => t.id);
  // const newArr = list.filter((t) => !existIds.includes(t.id));
  // if (newArr.length) {
  //   newArr.forEach((item: any) => {
  //     const obj = item;
  //     obj.envs = [];
  //     obj.showInMind = 0;
  //   });
  //   await projects.insertMany(newArr);
  // }
  await compareProject(list, 0);
  return list;
};

// 获取所有列表
export const syncProjects = async (page = 1) => {
  const list = await pullProject(page);
  if (list.length >= 100) {
    await syncProjects(page + 1);
  } else if (list.length === 0) {
    return [];
  }
  return [];
};

// 本地数据库查询
export const syncProjectsLoc = async () => {
  const list = await projects.getList({}, undefined, 1, 100);
  return list;
};

// 删除集合（全部）
export const syncProjectsDrop = async () => {
  const result = await projects.deleteDrop();
  return result;
};

// 获取gitlab项目组
export const syncGetGroups = async () => {
  const list = await getGroups({
    private_token: privateToken,
    per_page: 100,
    page: 1,
  });
  return list;
};

// 按条件查询
export const syncProjectsSearch = async (params: any) => {
  // 名称。正则模糊查询
  const query: any = {};
  if (params.name) {
    query.name = new RegExp(params.name, 'i');
  }
  if (params.groupName) {
    query['namespace.name'] = params.groupName;
  }
  if (params.id) {
    query.id = params.id;
  }
  if (params.showInMind) {
    query.showInMind = params.showInMind;
  }
  return projects.getList(query, undefined, 1, 100);
};

// 删除某一项
export const syncProjectsDelete = async (params: any) => {
  const result = await projects.deleteOne(params);
  return result;
};

// 新增/编辑
export const syncProjectsEdit = async (params: any) => {
  if (params.id) {
    const res = await projects.update(
      {
        name: params.name,
        'namespace.name': params.namespace,
        envs: params.envs,
        showInMind: params.showInMind,
        position: params.position || 'left',
      },
      {
        id: params.id,
      },
    );
    return res;
  }
  const res = await projects.insert({
    name: params.name,
    'namespace.name': params.namespace,
    created_at: new Date(),
    envs: params.envs,
    showInMind: params.showInMind,
  });
  return res;
};

// 获取项目的所有分支
export const syncGetBranchesList = async (params: any) => {
  const res = await getBranchesList({
    private_token: privateToken,
    id: params.id,
    per_page: params.per_page || 100,
    page: params.page || 1,
  });
  return res;
};

// 获取项目某个分支的提交记录
export const syncGetBranchCommitList = async (params: any) => {
  const res = await getBranchCommitList({
    private_token: privateToken,
    id: params.id,
    ref_name: params.ref_name,
    per_page: params.per_page || 100,
    page: params.page || 1,
  });
  return res;
};

// 获取项目某个分支最后一次提交
export const syncGetBranchCommitLastest = async (params: any) => {
  const res = await getBranchCommitLastest({
    private_token: privateToken,
    id: params.id,
    sha: params.sha,
  });
  return res;
};

// 新建分支
export const syncPostNewBranch = async (params: any) => {
  const res = await postNewBranch({
    private_token: privateToken,
    id: params.id,
    ref: params.ref,
    branch: params.branch,
  });
  return res;
};

// 获取某一个分支的信息
export const syncGetSingleBranch = async (params: any) => {
  const res = await getSingleBranch({
    id: params.id,
    branch: params.branch,
    private_token: privateToken,
  });
  return res;
};

// 创建合并请求
export const syncPostNewMR = async (params: any) => {
  const { token, project_name } = params;
  // 获取当前项目的主分支
  const res: any = await syncProjectsSearch({ id: params.id });
  const queryCondition = {
    $or: [
      { unionBranch: params.source_branch, project_id: params.id },
      { branch: params.source_branch, project_id: params.id },
    ],
  };
  const { default_branch } = res[0];
  const res2: any = await postNewMR({ ...params, target_branch: default_branch, private_token: privateToken }).catch((err: any) => Promise.reject(err));
  // 日志
  try {
    const info: any = await analysisToken(token);
    addLogs(2, 6, info.personName, [project_name], info.personId);
  } catch (err) {
    console.log(err);
  }
  if (res2.iid) {
    const res3: any = await storyWithproject.getList(queryCondition);
    if (res3 && Array.isArray(res3)) {
      res3.forEach((item) => {
        const i = item;
        i.mr = res2.iid;
        i.isMergeToMain = 2; // 把合并到主分支状态变成合并中
      });
      let index = 0;
      const test = async function test() {
        if (index >= res3.length) return;
        const x = res3[index];
        await storyWithproject.update(x, { _id: new ObjectId(x._id) });
        index += 1;
        test();
      };
      test();
      // // const res4 = await storyWithproject.update(res3, queryCondition);
      return true;
    }
  }
  return new Error('创建合并请求失败');
};
/**
 * 验证开发分支是否已经合并到主分支
 * @param params 请求参数，id 项目id, source_branch 开发分支
 * @returns boolean
 */
export const validMergeStatus = async (params: any) => {
  // 获取当前项目的主分支
  const { id, default_branch, source_branch } = params;
  if (!default_branch) {
    throw new Error('获取默认分支失败');
  }
  const res1: any = await syncGetBranchCommitLastest({ id, sha: default_branch });
  const sha = res1.id;
  const res2: any = await getRefs({ id, sha, private_token: privateToken });
  if (res2.length > 0) {
    const res3 = res2.some((t: any) => t.name === source_branch);
    return res3;
  }
  return false;
};
/**
 * 验证开发分支是否合并过最新主分支代码
 * @param params 请求参数，id 项目id, source_branch 开发分支
 * @returns boolean
 */
export const validDevMergeStatus = async (params: any) => {
  try {
    const { id, default_branch, source_branch } = params;
    if (!default_branch) {
      throw new Error('获取默认分支失败');
    }
    const res1: any = await syncGetBranchCommitLastest({ id, sha: source_branch });
    const sha = res1.id;
    const res2: any = await getRefs({ id, sha, private_token: privateToken });
    if (res2.length > 0) {
      const res3 = res2.some((t: any) => t.name === default_branch);
      return res3;
    }
  } catch (error) {
    console.error(error);
  }
  return false;
};
/**
 * 获取项目分支列表
 * @param id 项目id
 * @param page 页码
 * @param pageSize 每页条数
 * @param list 项目列表
 */
const getBranches = async (id, page: number, pageSize, list) => {
  const branches = await syncGetBranchesList({
    private_token: privateToken,
    id,
    per_page: pageSize,
    page,
  });
  list.push(...branches);
  if (branches.length >= pageSize) {
    await getBranches(id, page + 1, pageSize, list);
  }
};
/**
 * 递归方式验证分支是否合并过主分支
 * @param items 分支列表
 * @param project 当前项目信息
 * @param index 当前分支索引
 * @returns void
 */
const handleValidBranch = async (items: any, project: any, index: number) => {
  if (items.length <= index) {
    return;
  }
  const { id, default_branch } = project;
  const t = items[index];
  if (!t.merged && project.default_branch !== t.name && !t.name.includes('merge') && !t.name.includes('_uat_')) {
    const currentDate = dayjs();
    if (t.commit) {
      const date = dayjs(t.commit.created_at);
      if (Math.abs(date.diff(currentDate, 'week')) < 1) {
        const devRet = await validDevMergeStatus({ id, default_branch, source_branch: t.name });
        // devRet为true时，表示分支已上线
        if (!devRet) {
          const ret = await validMergeStatus({ id, default_branch, source_branch: t.name });
          if (!ret) {
            project.list.push({ name: t.name, commitInfo: t.commit });
          }
        }
      }
    }
  }
  await handleValidBranch(items, project, index + 1);
};
/**
 * 处理分支，获取项目的所有分支，并请求验证方法
 * @param item 当前项目
 */
const handleBranches = async (item: any) => {
  try {
    const branchList = [];
    const pageSize = 100;
    const page = 1;
    await getBranches(item.id, page, pageSize, branchList);
    await handleValidBranch(branchList, item, 0);
  } catch (error) {
    console.error(item, 'gitlab有错误的项目error<<<item');
  }
};
/**
 * 处理项目
 * @param items 项目列表
 * @param index 当前项目索引
 * @param list 结果
 * @returns void
 */
const handleProjects = async (items: any, index = 0, list: any[] = []) => {
  if (items.length <= index) {
    return;
  }
  const item = items[index];
  // 判断是不是前端组的项目。gitlab上有easyhome-frontend和easyhome-fe两个代码组
  // 只检测前端组的代码
  const {
    namespace: { path },
  } = item;
  if (['easyhome-frontend', 'easyhome-fe'].includes(path)) {
    const project: any = {
      id: item.id,
      name: item.name,
      default_branch: item.default_branch,
      list: [],
    };
    await handleBranches(project);
    list.push(project);
    await handleProjects(items, index + 1, list);
  }
};

// 获取本周本月的时间戳
const queryTime = () => {
  let day_s = 0;
  let day_e = 0;
  let week_s = 0;
  let week_e = 0;
  let month_s = 0;
  let month_e = 0;
  // 每天的时间戳
  day_s = dayjs().startOf('day').valueOf();
  day_e = dayjs().endOf('day').valueOf();
  // 获取本周周一周日的时间戳
  week_s = dayjs().startOf('week').valueOf();
  week_e = dayjs().endOf('week').valueOf();
  month_s = dayjs().startOf('month').valueOf();
  month_e = dayjs().endOf('month').valueOf();
  return {
    day_s,
    day_e,
    week_s,
    week_e,
    month_s,
    month_e,
  };
};

// 根据author，id、branch查询这个人在本周和本月的时间范围内出现的次数

const queryCount = async (author, times) => {
  const { day_s, day_e, week_s, week_e, month_s, month_e } = times;
  // 获取当天统计的次数
  const res2 = await mergeLog.getCount({
    createAt: {
      $gt: day_s, // 大于
      $lt: day_e, // 小于
    },
    author,
  });
  // 获取本周统计的次数
  const res = await mergeLog.getCount({
    createAt: {
      $gt: week_s, // 大于
      $lt: week_e, // 小于
    },
    author,
  });
  // 获取本月统计的次数
  const res1 = await mergeLog.getCount({
    createAt: {
      $gt: month_s, // 大于
      $lt: month_e, // 小于
    },
    author,
  });
  return {
    author,
    dayCount: res2,
    weekCount: res,
    monthCount: res1,
  };
};

// 统计每个人
const countEveryOne = async (data) => {
  const temp: any = [];
  const times = queryTime();
  // for (let i = 0; i < data.length; i += 1) {
  //   const { id, author, branch, name } = data[i];
  //   const res = await queryCount(author, id, name, branch, ...times);
  // }
  let index = 0;
  async function loop() {
    const author = data[index];
    const r = await queryCount(author, times);
    temp.push(r);
    index += 1;
    if (index < data.length) {
      await loop();
    }
  }
  await loop();
  return temp;
};

// 生成每个人的文案表格
const renderTexts = (data: { author: string; dayCount: number; weekCount: number; monthCount: number }[]) => {
  // { author: '李国宾', dayCount: 0, weekCount: 0, monthCount: 18 },
  const texts: string[] = [`#### 未合并主分支次数统计 ${dayjs().format('YYYY-MM-DD')}`, '示例：姓名[今天未合并项目数，本周提醒项目数，本月提醒项目数]'];
  // 过滤一下当天为0的
  let temp = data.filter((item) => item.dayCount > 0);
  // 按月、周、天倒序排序
  temp = temp.sort((a, b) => {
    if (b.monthCount - a.monthCount === 0) {
      if (b.weekCount - a.weekCount === 0) {
        return b.dayCount - a.dayCount;
      }
      return b.weekCount - a.weekCount;
    }
    return b.monthCount - a.monthCount;
  });
  for (let i = 0; i < temp.length; i += 1) {
    const { author, dayCount, weekCount, monthCount } = temp[i];
    const link = `http://59.110.10.239:8083/funcManage/mergeLogs?name=${temp[i].author}`;
    const text = `- [${author}[${dayCount}, ${weekCount}, ${monthCount}]](${link})`;
    texts.push(text);
  }
  return texts;
};

// 统计每个人每周每月的未合并次数
export const handleCounts = async () => {
  // 获取所有前端
  const res = await syncGetPersons({ _id: '' });
  const ret = res.map((item) => item.name);
  const result = await countEveryOne(ret);
  const texts = renderTexts(result);
  // 只有标题没有数据，就不发通知了。
  if (texts.length === 2) return;
  // console.log(texts);
  // 发钉钉通知
  ddSendMergeMasterCountMsg('未合并主分支次数统计', texts);
};

export const recentBranches = async () => {
  const currentProjects = await syncProjectsLoc();
  const list: any[] = [];
  await handleProjects(currentProjects, 0, list);
  const ret: any[] = [];
  const groupObj: { [key: string]: any[] } = {};
  list.forEach((t) => {
    if (t.list.length <= 0) {
      return;
    }
    const { id, name } = t;
    const createAt = Date.now();
    t.list.forEach((item) => {
      // 判断分支名字是不是含有uat字样。mergeUat\uat都认为是uat
      if (!isUat(item.name)) {
        const obj = {
          id,
          name,
          branch: item.name,
          commitDate: dayjs(item.commitInfo.created_at).format('YYYY-MM-DD HH:mm:ss'),
          message: item.commitInfo.message,
          author: item.commitInfo.author_name,
          createAt,
        };
        if (!groupObj[item.commitInfo.author_name]) {
          groupObj[item.commitInfo.author_name] = [];
        }
        groupObj[item.commitInfo.author_name].push(obj);
        ret.push(obj);
      }
    });
  });
  mergeLog.insertMany(ret);

  const chineseArr: string[] = [];
  const otherArr: string[] = [];
  Object.keys(groupObj).forEach((item) => {
    if (/[\u4e00-\u9fa5]/.test(item)) {
      chineseArr.push(item);
    } else {
      otherArr.push(item);
    }
  });
  // Object.keys(groupObj).forEach((user) => {
  //   if (user === '李国宾') {
  //     sendMsgUnMergeLog([user], '开发分支未合并主分支通知', `有${groupObj[user].length}个开发分支未合并主分支，请及时处理。`);
  //   }
  // });
  // 注释掉。不发钉钉工作通知了。
  // for (let i = 0; i < chineseArr.length; i += 1) {
  //   const t = chineseArr[i];
  //   const content: string[] = [];
  //   const items = groupObj[t];
  //   items.forEach((item: { name: string; branch: string }) => {
  //     content.push(`${item.name}\t|\t${item.branch}`);
  //   });
  //   // eslint-disable-next-line no-await-in-loop
  //   await sendMsgUnMergeLog([t], `有${items.length}个开发分支未合并`, content.join('\n\n'));
  // }
  // const otherContent = otherArr.length > 0 ? ['请以下同学将gitlab昵称改为真实姓名：'] : [];
  // otherArr.forEach((t: string) => {
  //   const items = groupObj[t];
  //   otherContent.push(`${t}：${items.length}个开发分支。`);
  // });
  // sendMsgMergeDone('开发分支未合并主分支通知', [`共有${ret.length}个开发分支未合并主分支，请及时处理`, ...otherContent, `访问链接：http://59.110.10.239:8083/funcManage/mergeLogs`]);
  // 往前端群里发每个人每天每周每月的次数
  handleCounts();
  return groupObj;
};

/**
 * 获取项目列表
 * @returns list
 */
export async function getAllProjects() {
  const oldList = await projects.getList(undefined, undefined, 1, 100);
  return oldList.map((t) => ({
    _id: t._id,
    name: t.name,
    web_url: t.web_url,
    default_branch: t.default_branch,
    envs: t.envs,
  }));
}

// 按条件查询
export const getProjectList = async (params: any) => {
  // 名称。正则模糊查询
  const query: any = {};
  if (params.name) {
    query.name = new RegExp(params.name);
  }
  if (params.groupName) {
    query['namespace.name'] = params.groupName;
  }
  if (params.id) {
    query.id = params.id;
  }
  if (params.showInMind) {
    query.showInMind = params.showInMind;
  }
  const page = Number(params.page) || 1;
  const pageSize = Number(params.pageSize) || 10;

  const count = await projects.getCount(query);
  const list = await projects.getList(query, undefined, page, pageSize);
  return {
    total: count,
    list,
  };
};
